home *** CD-ROM | disk | FTP | other *** search
- #!/bin/bash
- # Copyright 1999-2006 Gentoo Foundation
- # Distributed under the terms of the GNU General Public License v2
- # $Id: etc-update 2221 2005-11-01 01:32:07Z vapier $
-
- # Author Brandon Low <lostlogic@gentoo.org>
- #
- # Previous version (from which I've borrowed a few bits) by:
- # Jochem Kossen <j.kossen@home.nl>
- # Leo Lipelis <aeoo@gentoo.org>
- # Karl Trygve Kalleberg <karltk@gentoo.org>
-
- export PORTAGE_CALLER="etc-update"
-
- if type -p gsed >/dev/null ; then
- function sed() { gsed "$@"; }
- fi
-
- function get_config() {
- item=$1
-
- # First strip off comment lines, then grab the configuration
- # item. If there's more than one of the same configuration item,
- # then allow the last setting to take precedence.
- cut -d'#' -f1-1 /etc/etc-update.conf | \
- sed -ne "s/^ *$item *= *\([\"']\{0,1\}\)\(.*\)\1/\2/p" |sed -e '$p;d'
- }
-
- function scan() {
-
- echo "Scanning Configuration files..."
- rm -rf ${TMP}/files > /dev/null 2>&1
- mkdir ${TMP}/files || die "Failed mkdir command!" 1
- count=0
- input=0
-
- # Sanity check to make sure diff exists and works
- if ! diff -v &>/dev/null ; then
- echo "ERROR: 'diff' does not seem to work, aborting"
- exit 1
- fi
-
- for path in ${CONFIG_PROTECT} ; do
- [ ! -d ${path} ] && continue
-
- ofile=""
- for file in $(find ${path}/ -iname '._cfg????_*' ! -name '.*~' ! -name '.*.bak' |
- sed -e "s:\(^.*/\)\(\._cfg[0-9]*_\)\(.*$\):\1\2\3\%\2\%\3:" |
- sort -t'%' -k3 -k2 | LANG=POSIX LC_ALL=POSIX cut -f1 -d'%'); do
- rpath=$(echo "${file/\/\///}" | sed -e "s:/[^/]*$::")
- rfile=$(echo "${file/\/\///}" | sed -e "s:^.*/::")
- for mpath in ${CONFIG_PROTECT_MASK}; do
- if [[ "${rpath}" == "${mpath}"* ]]; then
- mv ${rpath}/${rfile} ${rpath}/${rfile:10}
- break
- fi
- done
- [ ! -f ${file} ] && continue
-
-
- if [[ "${ofile:10}" != "${rfile:10}" ]] ||
- [[ ${opath} != ${rpath} ]]; then
- MATCHES=0
- if [[ "${EU_AUTOMERGE}" == "yes" ]]; then
- if [ ! -e "${rpath}/${rfile}" ] || [ ! -e "${rpath}/${rfile:10}" ]; then
- MATCHES=0
- else
- diff -Bbua ${rpath}/${rfile} ${rpath}/${rfile:10} | egrep '^[+-]' | egrep -v '^[+-][\t ]*#|^--- |^\+\+\+ ' | egrep -qv '^[-+][\t ]*$'
- MATCHES=$?
- fi
- elif [[ -z $(diff -Nua ${rpath}/${rfile} ${rpath}/${rfile:10}|
- grep "^[+-][^+-]"|grep -v '# .Header:.*') ]]; then
- MATCHES=1
- fi
- if [[ "${MATCHES}" == "1" ]]; then
- echo "Automerging trivial changes in: ${rfile:10}"
- mv ${rpath}/${rfile} ${rpath}/${rfile:10}
- continue
- else
- count=${count}+1
- echo "${rpath}/${rfile:10}" > ${TMP}/files/${count}
- echo "${rpath}/${rfile}" >> ${TMP}/files/${count}
- ofile="${rfile}"
- opath="${rpath}"
- continue
- fi
- fi
-
- if [[ -z $(diff -Nua ${rpath}/${rfile} ${rpath}/${ofile}|
- grep "^[+-][^+-]"|grep -v '# .Header:.*') ]]; then
- mv ${rpath}/${rfile} ${rpath}/${ofile}
- continue
- else
- echo "${rpath}/${rfile}" >> ${TMP}/files/${count}
- ofile="${rfile}"
- opath="${rpath}"
- fi
- done
- done
-
- }
-
- function sel_file() {
- local -i isfirst=0
- until [[ -f ${TMP}/files/${input} ]] || \
- [[ ${input} == -1 ]] || \
- [[ ${input} == -3 ]]
- do
- local numfiles=$(ls ${TMP}/files|wc -l)
- local numwidth=${#numfiles}
- for file in $(ls ${TMP}/files|sort -n); do
- if [[ ${isfirst} == 0 ]] ; then
- isfirst=${file}
- fi
- numshow=$(printf "%${numwidth}i${PAR} " ${file})
- numupdates=$(( $(wc -l <${TMP}/files/${file}) - 1 ))
- echo -n "${numshow}"
- if [[ ${mode} == 0 ]] ; then
- echo "$(head -n1 ${TMP}/files/${file}) (${numupdates})"
- else
- head -n1 ${TMP}/files/${file}
- fi
- done > ${TMP}/menuitems
-
- if [ "${OVERWRITE_ALL}" == "yes" ]; then
- input=0
- else
- if [[ ${mode} == 0 ]] ; then
- echo "The following is the list of files which need updating, each
- configuration file is followed by a list of possible replacement files."
- else
- local my_title="Please select a file to update"
- fi
-
- if [[ ${mode} == 0 ]] ; then
- cat ${TMP}/menuitems
- echo "Please select a file to edit by entering the corresponding number."
- echo " (don't use -3 or -5 if you're unsure what to do)"
- echo " (-1 to exit) (-3 to auto merge all remaining files)"
- echo -n " (-5 to auto-merge AND not use 'mv -i'): "
- read input
- else
- dialog --title "${title}" --menu "${my_title}" \
- 0 0 0 $(echo -e "-1 Exit\n$(<${TMP}/menuitems)") \
- 2> ${TMP}/input || die "User termination!" 0
- input=$(<${TMP}/input)
- fi
- if [[ ${input} == -5 ]] ; then
- input=-3
- export mv_opts=""
- fi
- if [[ ${input} == -3 ]] ; then
- input=0
- export OVERWRITE_ALL="yes"
- fi
- fi # -3 automerge
- if [[ -z ${input} ]] || [[ ${input} == 0 ]] ; then
- input=${isfirst}
- fi
- done
- }
-
- function do_file() {
- echo
- local -i my_input
- local -i fcount=0
- until (( $(wc -l < ${TMP}/files/${input}) < 2 )); do
- my_input=0
- if (( $(wc -l < ${TMP}/files/${input}) == 2 )); then
- my_input=1
- fi
- until (( ${my_input} > 0 )) && (( ${my_input} < $(wc -l < ${TMP}/files/${input}) )); do
- fcount=0
-
- if [ "${OVERWRITE_ALL}" == "yes" ]; then
- my_input=0
- else
- for line in $(<${TMP}/files/${input}); do
- if (( ${fcount} > 0 )); then
- echo -n "${fcount}${PAR} "
- echo "${line}"
- else
- if [[ ${mode} == 0 ]] ; then
- echo "Below are the new config files for ${line}:"
- else
- local my_title="Please select a file to process for ${line}"
- fi
- fi
- fcount=${fcount}+1
- done > ${TMP}/menuitems
-
- if [[ ${mode} == 0 ]] ; then
- cat ${TMP}/menuitems
- echo -n "Please select a file to process (-1 to exit this file): "
- read my_input
- else
- dialog --title "${title}" --menu "${my_title}" \
- 0 0 0 $(echo -e "$(<${TMP}/menuitems)\n${fcount} Exit") \
- 2> ${TMP}/input || die "User termination!" 0
- my_input=$(<${TMP}/input)
- fi
- fi # OVERWRITE_ALL
-
- if [[ ${my_input} == 0 ]] ; then
- my_input=1
- elif [[ ${my_input} == -1 ]] ; then
- input=0
- return
- elif [[ ${my_input} == ${fcount} ]] ; then
- break
- fi
- done
- if [[ ${my_input} == ${fcount} ]] ; then
- break
- fi
-
- fcount=${my_input}+1
-
- file=$(sed -e "${fcount}p;d" ${TMP}/files/${input})
- ofile=$(head -n1 ${TMP}/files/${input})
-
- do_cfg "${file}" "${ofile}"
-
- sed -e "${fcount}!p;d" ${TMP}/files/${input} > ${TMP}/files/sed
- mv ${TMP}/files/sed ${TMP}/files/${input}
-
- if [[ ${my_input} == -1 ]] ; then
- break
- fi
- done
- echo
- rm ${TMP}/files/${input}
- count=${count}-1
- }
-
- function do_cfg() {
-
- local file="${1}"
- local ofile="${2}"
- local -i my_input=0
-
- until (( ${my_input} == -1 )) || [ ! -f ${file} ]; do
- if [ "${OVERWRITE_ALL}" == "yes" ]; then
- my_input=1
- else
- showdiffcmd=$(echo "${diff_command}" |
- sed -e "s:%file1:${ofile}:" -e "s:%file2:${file}:")
-
- if [ "${using_editor}" == 0 ]; then
- (
- echo "Showing differences between ${ofile} and ${file}"
- ${showdiffcmd}
- ) | ${pager}
- else
- echo "Beginning of differences between ${ofile} and ${file}"
- ${showdiffcmd}
- echo "End of differences between ${ofile} and ${file}"
- fi
- if [ -L "${file}" ]; then
- echo
- echo "-------------------------------------------------------------"
- echo "NOTE: File is a symlink to another file. REPLACE recommended."
- echo " The original file may simply have moved. Please review."
- echo "-------------------------------------------------------------"
- echo
- fi
- echo -n "1) Replace original with update
- 2) Delete update, keeping original as is
- 3) Interactively merge original with update
- 4) Show differences again
- Please select from the menu above (-1 to ignore this update): "
- read my_input
- fi
-
- case ${my_input} in
- 1) echo "Replacing ${ofile} with ${file}"
- mv ${mv_opts} ${file} ${ofile}
- my_input=-1
- continue
- ;;
- 2) echo "Deleting ${file}"
- rm ${rm_opts} ${file}
- continue
- ;;
- 3) do_merge "${file}" "${ofile}"
- my_input=${?}
- # [ ${my_input} == 255 ] && my_input=-1
- continue
- ;;
- 4) continue
- ;;
- *) continue
- ;;
- esac
- done
- }
-
- function do_merge() {
-
- local file="${1}"
- local ofile="${2}"
- local mfile="${2}.merged"
- local -i my_input=0
- echo "${file} ${ofile} ${mfile}"
-
- if [ -e ${mfile} ] ; then
- echo "A previous version of the merged file exists, cleaning..."
- rm ${rm_opts} ${mfile}
- fi
-
- until (( ${my_input} == -1 )); do
- echo "Merging ${file} and ${ofile}"
- $(echo "${merge_command}" |
- sed -e "s:%merged:${mfile}:g" \
- -e "s:%orig:${ofile}:g" \
- -e "s:%new:${file}:g")
- until (( ${my_input} == -1 )); do
- echo -n "1) Replace ${ofile} with merged file
- 2) Show differences between merged file and original
- 3) Remerge original with update
- 4) Edit merged file
- 5) Return to the previous menu
- Please select from the menu above (-1 to exit, losing this merge): "
- read my_input
- case ${my_input} in
- 1) echo "Replacing ${ofile} with ${mfile}"
- chmod --reference=${ofile} ${mfile}
- mv ${mv_opts} ${mfile} ${ofile}
- rm ${rm_opts} ${file}
- return 255
- ;;
- 2) ( echo "Showing differences between ${ofile} and ${mfile}"
- $(echo "${diff_command}" | \
- sed -e "s:%file1:${ofile}:" \
- -e "s:%file2:${mfile}:") ) | ${pager}
- continue
- ;;
- 3) break
- ;;
- 4) ${EDITOR:-nano -w} "${mfile}"
- continue
- ;;
- 5) rm ${rm_opts} ${mfile}
- return 0
- ;;
- *) continue
- ;;
- esac
- done
- done
- rm ${rm_opts} ${mfile}
- return 255
- }
-
- function die() {
- trap "" TERM
- trap "" KILL
- echo "Exiting: ${1}"
- rm -rf ${TMP}
- exit ${2}
- }
-
- #
- # Run the script
- #
- scriptname=$(basename $0)
-
- trap die term
-
- export PORTAGE_TMPDIR=$(/usr/lib/portage/bin/portageq envvar PORTAGE_TMPDIR)
-
- TMP="${PORTAGE_TMPDIR}/$$"
- rm -rf ${TMP} 2> /dev/null
- mkdir ${TMP} || die "failed mkdir command!" 1
-
- # I need the CONFIG_PROTECT value
- CONFIG_PROTECT=$(/usr/lib/portage/bin/portageq envvar CONFIG_PROTECT)
- CONFIG_PROTECT_MASK=$(/usr/lib/portage/bin/portageq envvar CONFIG_PROTECT_MASK)
-
- # load etc-config's configuration
- EU_AUTOMERGE=$(get_config eu_automerge)
- rm_opts=$(get_config rm_opts)
- mv_opts=$(get_config mv_opts)
- cp_opts=$(get_config cp_opts)
- pager=$(get_config pager)
- diff_command=$(get_config diff_command)
- using_editor=$(get_config using_editor)
- merge_command=$(get_config merge_command)
- declare -i mode=$(get_config mode)
- [ -z ${mode} ] && mode=0
- [ -z "${pager}" ] && pager="cat"
-
- #echo "rm_opts: $rm_opts, mv_opts: $mv_opts, cp_opts: $cp_opts"
- #echo "pager: $pager, diff_command: $diff_command, merge_command: $merge_command"
-
- if (( ${mode} == 0 )); then
- PAR=")"
- else
- PAR=""
- fi
-
- declare -i count=0
- declare input=0
- declare title="Gentoolkit's etc-update tool!"
-
- scan
-
- until (( ${input} == -1 )); do
- if (( ${count} == 0 )); then
- die "Nothing left to do; exiting. :)" 0
- fi
- sel_file
- if (( ${input} != -1 )); then
- do_file
- fi
- done
-
- die "User termination!" 0
-